/**
 * Copyright 2009 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.code.sapien.action;

import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;

import com.google.code.sapien.ActionConstants;
import com.google.code.sapien.model.CategoryAcl;
import com.google.code.sapien.model.User;
import com.google.code.sapien.security.SecurityDetails;
import com.google.code.sapien.security.SapienSecurityDetails;
import com.google.code.sapien.service.CategoryAclService;
import com.google.code.sapien.service.UserService;
import com.google.inject.Inject;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;

/**
 * Authentication Action, used to authenticate users for login.
 * @author Adam
 * @version $Id: AuthenticateAction.java 29 2010-01-04 05:25:44Z a.ruggles $
 * 
 * Created on Apr 21, 2009 at 9:55:12 PM 
 */
@Results({
	@Result(name = "input", location = "login.jsp"),
	@Result(name = "error", location = "login.jsp"),
	@Result(name = "success", params = {"actionName", "index", "namespace", "/" }, type = "redirectAction")
})
public class AuthenticateAction extends ActionSupport implements SessionAware, ServletRequestAware,
	ServletResponseAware {
	/**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = 7475174448787235699L;

	/**
	 * The category ACL service.
	 */
	private final CategoryAclService categoryAclService;

	/**
	 * The password.
	 */
	private String password;

	/**
	 * Should we persist the login "remember me". 
	 */
	private boolean remember;

	/**
	 * The HttpServletRequest.
	 */
	private HttpServletRequest request;

	/**
	 * The HttpServletResponse.
	 */
	private HttpServletResponse response;

	/**
	 * The session map.
	 */
	private Map<String, Object> session;

	/**
	 * The username.
	 */
	private String username;

	/**
	 * The user service.
	 */
	private final UserService userService;

	/**
	 * Constructs an authentication action.
	 * @param userService The user service.
	 * @param categoryAclService The category ACL service.
	 */
	@Inject
	public AuthenticateAction(final UserService userService, final CategoryAclService categoryAclService) {
		super();
		this.userService = userService;
		this.categoryAclService = categoryAclService;
	}

	/**
	 * {@inheritDoc}
	 * @see com.opensymphony.xwork2.ActionSupport#execute()
	 */
	public String execute() {
		final User user = userService.validate(username, password);
		if (user == null) {
			super.addActionError(getText("validation.authentication.error",
					"Username or password did not match any users."));
			return ERROR;
		} else {
			final List<CategoryAcl> acls = categoryAclService.list(user.getRoles());
			final SecurityDetails securityDetails = new SapienSecurityDetails(user, acls);
			securityDetails.setIpAddress(request.getRemoteAddr());
			session.put(ActionConstants.USER_SESSION, securityDetails);
			if (remember) {
				final String encryptedMessage = userService.addPersistentLogin(user);
				final Cookie cookie = new Cookie(ActionConstants.USER_PERSISTENT_LOGIN, encryptedMessage);
				cookie.setMaxAge(ActionConstants.USER_PERSISTENT_LOGIN_AGE);
				response.addCookie(cookie);
			}
		}
		return SUCCESS;
	}

	/**
	 * Returns password.
	 * @return the password.
	 */
	@RequiredStringValidator(message = "Invalid password.", key = "validation.invalid.password")
	public String getPassword() {
		return password;
	}

	/**
	 * Returns username.
	 * @return the username.
	 */
	@RequiredStringValidator(message = "Invalid username.", key = "validation.invalid.username")
	public String getUsername() {
		return username;
	}

	/**
	 * Returns remember.
	 * @return the remember.
	 */
	public boolean isRemember() {
		return remember;
	}

	/**
	 * Sets password.
	 * @param password the password to set.
	 */
	public void setPassword(final String password) {
		this.password = password;
	}

	/**
	 * Sets remember.
	 * @param remember the remember to set.
	 */
	public void setRemember(final boolean remember) {
		this.remember = remember;
	}

	/**
	 * {@inheritDoc}
	 * @see org.apache.struts2.interceptor.ServletRequestAware#setServletRequest(javax.servlet.http.HttpServletRequest)
	 */
	public void setServletRequest(final HttpServletRequest request) {
		this.request = request;
	}

	/**
	 * {@inheritDoc}
	 * @see org.apache.struts2.interceptor.ServletResponseAware#setServletResponse(
	 * javax.servlet.http.HttpServletResponse)
	 */
	public void setServletResponse(final HttpServletResponse response) {
		this.response = response;
	}

	/**
	 * {@inheritDoc}
	 * @see org.apache.struts2.interceptor.SessionAware#setSession(java.util.Map)
	 */
	public void setSession(final Map<String, Object> session) {
		this.session = session;
	}

	/**
	 * Sets username.
	 * @param username the username to set.
	 */
	public void setUsername(final String username) {
		this.username = username;
	}
}
